package com.osfw.framework.web.controller;


import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.basic.SaBasicUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.temp.SaTempUtil;
import com.antherd.smcrypto.sm2.Sm2;
import com.osfw.framework.config.Global;
import com.osfw.framework.constants.Constants;
import com.osfw.framework.core.domain.RestfulResult;
import com.osfw.framework.utils.CookieUtils;
import com.osfw.framework.utils.DateUtils;
import com.osfw.framework.utils.http.RequestUtil;
import com.osfw.framework.web.service.PasswordService;
import com.osfw.system.entity.manage.SysUser;
import com.osfw.system.service.manage.ISysUserService;
import com.sun.jndi.toolkit.url.UrlUtil;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;

/**
 * 钥匙库
 */
@Controller
@RequestMapping("/osfw")
public class AuthController {
    private String prefix = "osfw/common";


    @Autowired
    private ISysUserService userService;
    @Autowired
    private PasswordService passwordService;


    @SaIgnore
    @GetMapping("/auth")
    public String auth(ModelMap mmap, HttpServletRequest request, HttpServletResponse response) {
        if(Global.isSaBasicEnabled()) {
            SaBasicUtil.check(Constants.BASIC_AUTH + "@" + DateUtils.getHour(new Date()));
        }
        mmap.put("tempUrl", RequestUtil.getBasePath(request) + "/osfw/dispatch");
        return prefix + "/error/auth";
    }

    @SneakyThrows
    @SaIgnore
    @GetMapping("/doAuth")
    @ResponseBody
    public String doAuth(ModelMap mmap, HttpServletRequest request, HttpServletResponse response) {
        if(Global.isSaBasicEnabled()) {
            SaBasicUtil.check(Constants.BASIC_AUTH + "@" + DateUtils.getHour(new Date()));
        }

        String tempToken = SaTempUtil.createToken(Constants.TEMP_TOKEN_NAME, Constants.TEMP_TOKEN_TIMEOUT + 1);
        CookieUtils.setCookie(response, Constants.TEMP_TOKEN_NAME, tempToken, (60 - DateUtils.getMinute(new Date())) * 60);
        StpUtil.getTokenSessionByToken(tempToken).set("expiryTime", System.currentTimeMillis() + (Constants.TEMP_TOKEN_TIMEOUT + 1) * 1000);

        mmap.put("tempUrl", RequestUtil.getBasePath(request) + "/osfw/dispatch");

        return new String(Base64.encodeBase64(UrlUtil.encode(RequestUtil.getBasePath(request) + "/osfw/dispatch", "UTF8").getBytes()));
    }

    @GetMapping("/dispatch")
    public String dispatch(ModelMap mmap, HttpServletRequest request, HttpServletResponse response) {
        if(Global.isSaBasicEnabled()) {
            SaBasicUtil.check(Constants.BASIC_AUTH + "@" + DateUtils.getHour(new Date()));
        }
        long expiryTime = StpUtil.getTokenSessionByToken(CookieUtils.getCookie(request, Constants.TEMP_TOKEN_NAME)).getLong("expiryTime");
        long currentTime = System.currentTimeMillis();
        long timeout = Integer.valueOf(String.valueOf((currentTime > expiryTime ? 0 : expiryTime - currentTime) / 1000));
        mmap.put("tempUrl", RequestUtil.getBasePath(request) + "/osfw/login");
        mmap.put("timeout", timeout);

        return prefix + "/error/dispatch";
    }

    @PostMapping("/openSafe")
    @ResponseBody
    public RestfulResult openSafe(@RequestParam String password) {
        String privateKey = StpUtil.getSession().get("privateKey").toString();
        password = Sm2.doDecrypt(password, privateKey);

        Long userId = StpUtil.getLoginIdAsLong();
        SysUser user = userService.selectUserById(userId);
        passwordService.validate(user, password);

        // 比对成功，为当前会话打开二级认证，有效期为 timeout 分钟
        StpUtil.openSafe(2 * 60);

        return RestfulResult.success("二级认证成功");
    }

    @SaIgnore
    @GetMapping("/error/401")
    public String unauthorized() {
        return prefix + "/error/401";
    }

    @SaIgnore
    @GetMapping("/error/403")
    public String forbidden() {
        return prefix + "/error/403";
    }

    @SaIgnore
    @GetMapping("/error/500")
    public String error() {
        return prefix + "/error/500";
    }

}
